package com.cjd.view;


import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;

import com.cjd.common.R;


/**
 * @Author chenjidong
 * @email 374122600@qq.com
 * created 2019/6/27
 * description 基于贝赛尔曲线绘制 三层 内部带海浪翻滚view
 */
public class BezierWaveView extends View {
    private Paint bgPaint, wavePaint;
    private Paint headsetLinePaint;
    private Paint textPaint;

    private Path wavePath;
    private Path clipPath;

    private ValueAnimator beforeAnimator, afterAnimator;

    private String hint = "";//base 下得提示文字

    private RectF headsetLineRectf, headsetRectf;
    private Rect textRect;

    private float beforeOffset, afterOffset;
    private int viewWidth, viewHeight;
    private int waveOffset = 100;//波浪高度
    private int progress = 50;
    private boolean isCircle = true;
    private int waveColor, bgColor, textColor;
    private int margin;
    private boolean headset = true;
    private int headsetMargin;
    private int headsetActiveColor;
    private float lineStrokeWidth = 10;
    private int fps = 60;
    private int radius;
    private boolean isSingleCircle = false;
    private int bgAlpha = 255, waveInsideAlpha = 100, waveOutsideAlpha = 255;

    public BezierWaveView(Context context) {
        super(context);
        init(context, null);
    }

    public BezierWaveView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);

    }

    public BezierWaveView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
//        setLayerType(View.LAYER_TYPE_SOFTWARE, null);//关闭硬件加速
        if (attrs != null) {
            TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.BezierWaveView);
            progress = array.getInt(R.styleable.BezierWaveView_bw_wave_progress, 40);

            bgColor = array.getColor(R.styleable.BezierWaveView_bw_bg_color, 0xffffffff);
            waveColor = array.getColor(R.styleable.BezierWaveView_bw_wave_color, 0xff00ff00);
            textColor = array.getColor(R.styleable.BezierWaveView_bw_text_color, 0xffff00ff);
            isCircle = array.getBoolean(R.styleable.BezierWaveView_bw_circle, true);
            waveOffset = array.getDimensionPixelOffset(R.styleable.BezierWaveView_bw_wave_offset, dp2px(30));
            headset = array.getBoolean(R.styleable.BezierWaveView_bw_headset, true);
            headsetMargin = array.getDimensionPixelOffset(R.styleable.BezierWaveView_bw_headset_margin, dp2px(8));
            headsetActiveColor = array.getColor(R.styleable.BezierWaveView_bw_headset_active_color, textColor);
            isSingleCircle = array.getBoolean(R.styleable.BezierWaveView_bw_single_circle, false);
            bgAlpha = array.getInteger(R.styleable.BezierWaveView_bw_bg_alpha, 255);
            waveOutsideAlpha = array.getInteger(R.styleable.BezierWaveView_bw_wave_outside_alpha, 255);
            waveInsideAlpha = array.getInteger(R.styleable.BezierWaveView_bw_wave_inside_alpha, 100);
            array.recycle();
        } else {
            waveColor = Color.WHITE;
            bgColor = Color.GRAY;
            textColor = Color.GREEN;
            headsetActiveColor = textColor;
        }
        if (headsetMargin < 0)
            headsetMargin = dp2px(8);

        margin = 0;
        wavePath = new Path();

        bgPaint = new Paint();
        bgPaint.setAntiAlias(true);
        bgPaint.setDither(true);
        bgPaint.setStyle(Paint.Style.FILL);
        bgPaint.setStrokeWidth(dp2px(3));

        wavePaint = new Paint(bgPaint);
        wavePaint.setColor(waveColor);


        headsetLinePaint = new Paint();
        headsetLinePaint.setColor(bgColor);
        headsetLinePaint.setStrokeWidth(lineStrokeWidth);
        headsetLinePaint.setAntiAlias(true);
        headsetLinePaint.setStyle(Paint.Style.STROKE);

        headsetLineRectf = new RectF();
        headsetRectf = new RectF();

        textPaint = new Paint();
        textRect = new Rect();

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        if (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED) {
            viewWidth = MeasureSpec.getSize(widthMeasureSpec);
        } else
            viewWidth = getResources().getDisplayMetrics().widthPixels;

        if (MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.UNSPECIFIED) {
            viewHeight = MeasureSpec.getSize(heightMeasureSpec);
        } else
            viewHeight = viewWidth > 0 ? viewWidth / 2 : dp2px(150);//默认高度


        initSize();
    }


    private void initSize() {
        radius = viewWidth / 2;
        margin = viewWidth / 5;

        if (isSingleCircle)
            margin = 0;

        clipPath = new Path();
        clipPath.addCircle(viewWidth / 2f, viewHeight / 2f, viewWidth / 2f - margin, Path.Direction.CCW);

        if (beforeAnimator == null || afterAnimator == null)
            initAnim();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
//        long time = System.currentTimeMillis();

        drawCircleBackground(canvas);

        drawWave(canvas);

        if (!TextUtils.isEmpty(hint)) {
            drawProcessText(canvas);
        }

//        long last = System.currentTimeMillis();
//        Log.d("--->", "onDraw: " + (last - time) + "ms");
    }

    /**
     * 绘制圆形 3层背景
     */
    private void drawCircleBackground(Canvas canvas) {
        //画背景圈圈 3层 和耳机
        if (isCircle) {
            bgPaint.setColor(bgColor);

            if (isSingleCircle) {
                bgPaint.setAlpha(bgAlpha);
                canvas.drawCircle(viewWidth / 2f, viewHeight / 2f, radius - margin, bgPaint);
            } else {
                bgPaint.setAlpha(55);
                canvas.drawCircle(viewWidth / 2f, viewHeight / 2f, radius - margin + 40, bgPaint);

                bgPaint.setAlpha(100);
                canvas.drawCircle(viewWidth / 2f, viewHeight / 2f, radius - margin + 20, bgPaint);

                bgPaint.setAlpha(255);
                canvas.drawCircle(viewWidth / 2f, viewHeight / 2f, radius - margin, bgPaint);

                if (headset) //耳机只适配多层背景情况 不能在单层中出现
                    drawHeadset(canvas);
            }
        }
    }


    private void drawWave(Canvas canvas) {
        canvas.save();
        if (isCircle) {//大小必须和第三层背景一致
            canvas.clipPath(clipPath);
        }

        //计算波浪真实基线
        int realProgress = (int) ((radius - margin) * 2 / 100f * progress);
        int viewY = viewHeight / 2 + radius - margin - realProgress;

        drawFirstLayerWave(canvas, viewY);
        drawSecondLayerWave(canvas, viewY);
        canvas.restore();
    }

    /**
     * 绘制耳机
     */
    private void drawHeadset(Canvas canvas) {
        float radius = viewWidth / 2f;
        float outsideRadius = radius - margin + 40;//最外部的圆半径
        //画耳机线
        headsetLinePaint.setStrokeWidth(lineStrokeWidth);
        headsetLinePaint.setStyle(Paint.Style.STROKE);
        float lineLeft = radius - outsideRadius - lineStrokeWidth - headsetMargin;
        float lineTop = viewHeight / 2f - outsideRadius - lineStrokeWidth - headsetMargin;
        float lineRight = radius + outsideRadius + lineStrokeWidth + headsetMargin;
        float lineBottom = viewHeight / 2f + outsideRadius + lineStrokeWidth + headsetMargin;


        headsetLineRectf.set(lineLeft, lineTop, lineRight, lineBottom);
        canvas.drawArc(headsetLineRectf, 180, 180, false, headsetLinePaint);

        headsetLinePaint.setColor(headsetActiveColor);
        float realSweepAngle = 180 / 100f * progress;
        canvas.drawArc(headsetLineRectf, 180, realSweepAngle, false, headsetLinePaint);

        //画耳朵
        headsetLinePaint.setStyle(Paint.Style.FILL);
        headsetLinePaint.setStrokeWidth(1);

        if (realSweepAngle > 0) {
            headsetLinePaint.setColor(headsetActiveColor);
        } else
            headsetLinePaint.setColor(bgColor);

        float width = (viewWidth - outsideRadius * 2f) / 2f;

        headsetRectf.set(0, viewHeight / 2f - width / 2f, width, viewHeight / 2f + width / 2f);

        headsetRectf.offset(lineLeft + lineStrokeWidth - (width / 2), 0);
        canvas.drawArc(headsetRectf, 86, 186, true, headsetLinePaint);

        if (realSweepAngle >= 180) {
            headsetLinePaint.setColor(headsetActiveColor);
        } else
            headsetLinePaint.setColor(bgColor);

        headsetRectf.offset(outsideRadius * 2f + headsetMargin * 2, 0);
        canvas.drawArc(headsetRectf, -90, 180, true, headsetLinePaint);

    }

    private void initAnim() {
        beforeAnimator = ValueAnimator.ofFloat(0, viewWidth);
        beforeAnimator.setRepeatCount(ValueAnimator.INFINITE);
        beforeAnimator.setDuration(2000);
        beforeAnimator.setInterpolator(new LinearInterpolator());
        beforeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            long lastTime;

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                beforeOffset = (float) animation.getAnimatedValue();

                if ((System.currentTimeMillis() - lastTime) > (1000 / fps))
                    invalidate();

                lastTime = System.currentTimeMillis();
            }
        });
        beforeAnimator.start();

        afterAnimator = ValueAnimator.ofFloat(viewWidth, 0);
        afterAnimator.setRepeatCount(ValueAnimator.INFINITE);
        afterAnimator.setDuration(2000);
        afterAnimator.setInterpolator(new LinearInterpolator());
        afterAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            long lastTime;

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                afterOffset = (float) animation.getAnimatedValue();

                if ((System.currentTimeMillis() - lastTime) > (1000 / fps))
                    invalidate();

                lastTime = System.currentTimeMillis();
            }
        });
        afterAnimator.start();
    }

    /**
     * 返回真实波浪高度
     *
     * @return
     */
    private int getRealWaveOffset() {
        return progress >= 100 || progress <= 0 ? 0 : waveOffset;
    }

    /**
     * 第一层波浪
     *
     * @param canvas 画布
     * @param viewY  波浪基线
     */
    private void drawFirstLayerWave(Canvas canvas, int viewY) {
        wavePath.reset();

        wavePaint.setColor(waveColor);
        wavePaint.setAlpha(waveOutsideAlpha);
        // 绘制屏幕外的波浪 需要减去当前屏幕的宽度 即屏幕左边
        wavePath.moveTo(beforeOffset - viewWidth, viewY);
        wavePath.quadTo(viewWidth / 4f + beforeOffset - viewWidth, viewY - getRealWaveOffset(), viewWidth / 2f + beforeOffset - viewWidth, viewY);
        wavePath.moveTo(viewWidth / 2f + beforeOffset - viewWidth, viewY);
        wavePath.quadTo(viewWidth / 4f * 3 + beforeOffset - viewWidth, viewY + getRealWaveOffset(), viewWidth + beforeOffset - viewWidth, viewY);

        // 绘制屏幕内的波浪
        wavePath.moveTo(beforeOffset, viewY);
        wavePath.quadTo(viewWidth / 4f + beforeOffset, viewY - getRealWaveOffset(), viewWidth / 2f + beforeOffset, viewY);
        wavePath.moveTo(viewWidth / 2f + beforeOffset, viewY);
        wavePath.quadTo(viewWidth / 4f * 3 + beforeOffset, viewY + getRealWaveOffset(), viewWidth + beforeOffset, viewY);

        //绘制封闭的区域
        wavePath.lineTo(viewWidth + beforeOffset, viewHeight);
        wavePath.lineTo(beforeOffset - viewWidth, viewHeight);
        wavePath.lineTo(beforeOffset - viewWidth, viewY);
        canvas.drawPath(wavePath, wavePaint);
    }

    /**
     * 第二层交叉 波浪 默认第二层透明度比第一层低
     *
     * @param canvas 画布
     * @param viewY  波浪基线
     */
    private void drawSecondLayerWave(Canvas canvas, int viewY) {
        wavePath.reset();
        wavePaint.setColor(waveColor);
        wavePaint.setAlpha(waveInsideAlpha);
        // 绘制屏幕外的波浪 需要减去当前屏幕的宽度 即屏幕左边
        wavePath.moveTo(afterOffset - viewWidth, viewY);
        wavePath.quadTo(viewWidth / 4f + afterOffset - viewWidth, viewY + getRealWaveOffset(), viewWidth / 2f + afterOffset - viewWidth, viewY);
        wavePath.moveTo(viewWidth / 2f + afterOffset - viewWidth, viewY);
        wavePath.quadTo(viewWidth / 4f * 3 + afterOffset - viewWidth, viewY - getRealWaveOffset(), viewWidth + afterOffset - viewWidth, viewY);

        // 绘制屏幕内的波浪
        wavePath.moveTo(afterOffset, viewY);
        wavePath.quadTo(viewWidth / 4f + afterOffset, viewY + getRealWaveOffset(), viewWidth / 2f + afterOffset, viewY);
        wavePath.moveTo(viewWidth / 2f + afterOffset, viewY);
        wavePath.quadTo(viewWidth / 4f * 3 + afterOffset, viewY - getRealWaveOffset(), viewWidth + afterOffset, viewY);

        //绘制封闭的区域
        wavePath.lineTo(viewWidth + afterOffset, viewHeight);
        wavePath.lineTo(afterOffset - viewWidth, viewHeight);
        wavePath.lineTo(afterOffset - viewWidth, viewY);

        canvas.drawPath(wavePath, wavePaint);
    }


    /**
     * 绘制进度文字
     *
     * @param canvas
     */
    private void drawProcessText(Canvas canvas) {


        textPaint.setAntiAlias(true);
        textPaint.setTextSize(dp2px(30));
        textPaint.setColor(textColor);
        //画布的大小
        textRect.set(0, 0, viewWidth, viewHeight);

        Paint.FontMetricsInt fontMetrics = textPaint.getFontMetricsInt();
        int baseline = (textRect.bottom + textRect.top - fontMetrics.bottom - fontMetrics.top) / 2;
        // 下面这行是实现水平居中，drawText对应改为传入textRect.centerX()
        textPaint.setTextAlign(Paint.Align.CENTER);
        String text = progress + "%";
        canvas.drawText(text, textRect.centerX(), baseline, textPaint);


        textPaint.setTextSize(dp2px(12));
        Paint.FontMetricsInt fontMetrics1 = textPaint.getFontMetricsInt();
        int baseline1 = viewHeight / 2 - ((fontMetrics1.bottom - fontMetrics1.top) / 2);

        canvas.drawText(hint, textRect.centerX(), baseline1 + ((fontMetrics.bottom - fontMetrics.top)), textPaint);

    }

    public void setProgress(int progress) {
        this.progress = progress;
    }

    /**
     * base 下得提示文字
     *
     * @param hint null 或者 "" 不显示  默认 ”已完成“
     */
    public void setHint(String hint) {
        this.hint = hint;
    }

    /**
     * pd转px
     *
     * @param dp dp值
     * @return 转换后的px值
     */
    private int dp2px(float dp) {
        float scale = Resources.getSystem().getDisplayMetrics().density;
        return (int) (dp * scale + 0.5f);
    }

}
